//this hash map use Poco::HashMap from poco and  inhert from GMap
//andycai_sc implement 2011-05-15

#ifndef GPOCOHASHMAP_H
#define GPOCOHASHMAP_H

#include "GTpl/IGMap.h"

#include "Poco/HashMap.h"

using std::pair;

template< typename Key, typename Value, typename HashFunc = Poco::Hash<Key> >
class GHashMap : public GMap<Key, Value>
{
public:
	GHashMap() {}
	virtual ~GHashMap() {}

	typename GMap<Key, Value>::IterPtr insert(const Key& key, const Value& value);

	int erase(const Key& key);
	void erase(typename GMap<Key, Value>::IterPtr position);

	typename GMap<Key, Value>::IterPtr find(const Key& key);

	typename GMap<Key, Value>::IterPtr begin();
	typename GMap<Key, Value>::IterPtr end();

private:
	Poco::HashMap<Key, Value, HashFunc> m_hashMap;
	class HIterator : public GMap<Key, Value>::Iterator
	{
	public:
		HIterator(typename Poco::HashMap<Key, Value, HashFunc>::Iterator& it) :
		m_iter(it)
		{
		}
		HIterator(const HIterator& hIt) :
		m_iter(hIt.m_iter)
		{
		}
		virtual ~HIterator() {}
		typename GMap<Key, Value>::Iterator* clone();
		const Key& getKey();
		Value& getValue();
		typename GMap<Key, Value>::Iterator& operator++();
		typename GMap<Key, Value>::Iterator& operator++(int);
		bool operator==(const typename GMap<Key, Value>::Iterator&) const;
		bool operator!=(const typename GMap<Key, Value>::Iterator&) const;

		typename Poco::HashMap<Key, Value, HashFunc>::Iterator getOrigIter() const
        {
            return m_iter;
        }
	private:
		typename Poco::HashMap<Key, Value, HashFunc>::Iterator m_iter;
	};
};

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::insert(const Key& key, const Value& value)
{
	pair< typename Poco::HashMap<Key, Value, HashFunc>::Iterator, bool > rp = m_hashMap.insert(typename Poco::HashMap<Key, Value, HashFunc>::PairType(key, value));
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(rp.first));
	return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
int GHashMap<Key, Value, HashFunc>::erase(const Key& key)
{
	int size = (m_hashMap.find(key) != m_hashMap.end()) ? 1 : 0;
	m_hashMap.erase(key);
	return size;
}

template<typename Key, typename Value, typename HashFunc>
void GHashMap<Key, Value, HashFunc>::erase(typename GMap<Key, Value>::IterPtr position)
{
    HIterator* hIt = dynamic_cast<HIterator*>(position.get());
    assert(hIt != 0);
    m_hashMap.erase(hIt->getOrigIter());
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::find(const Key& key)
{
	typename Poco::HashMap<Key, Value, HashFunc>::Iterator it = m_hashMap.find(key);
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
	return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::begin()
{
	typename Poco::HashMap<Key, Value, HashFunc>::Iterator it = m_hashMap.begin();
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
	return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::end()
{
	typename Poco::HashMap<Key, Value, HashFunc>::Iterator it = m_hashMap.end();
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
	return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator* GHashMap<Key, Value, HashFunc>::HIterator::clone()
{
	return new HIterator(*this);
}

template<typename Key, typename Value, typename HashFunc>
const Key& GHashMap<Key, Value, HashFunc>::HIterator::getKey()
{
	return m_iter->first;
}

template<typename Key, typename Value, typename HashFunc>
Value& GHashMap<Key, Value, HashFunc>::HIterator::getValue()
{
	return m_iter->second;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMap<Key, Value, HashFunc>::HIterator::operator++()
{
	m_iter++;
	return *this;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMap<Key, Value, HashFunc>::HIterator::operator++(int)
{
	++m_iter;
	return *this;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMap<Key, Value, HashFunc>::HIterator::operator==(const typename GMap<Key, Value>::Iterator& it) const
{
	const HIterator& hIt = dynamic_cast<const HIterator&>(it);
	return m_iter == hIt.m_iter;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMap<Key, Value, HashFunc>::HIterator::operator!=(const typename GMap<Key, Value>::Iterator& it) const
{
	const HIterator& hIt = dynamic_cast<const HIterator&>(it);
	return m_iter != hIt.m_iter;
}

//----------------------GHashMultiMap implement-----------------------------------------

#include <vector>

template< typename Key, typename Value, typename Container = std::vector<Value>, typename HashFunc = Poco::Hash<Key> >
class GHashMultiMap : public GMap<Key, Value>
{
public:
	GHashMultiMap() {}
	virtual ~GHashMultiMap() {}

	typename GMap<Key, Value>::IterPtr insert(const Key& key, const Value& value);

	int erase(const Key& key);
	void erase(typename GMap<Key, Value>::IterPtr position);

	typename GMap<Key, Value>::IterPtr find(const Key& key);

	typename GMap<Key, Value>::IterPtr begin();
	typename GMap<Key, Value>::IterPtr end();

	typename GMap<Key, Value>::Range equal_range(const Key& key);

private:
	Poco::HashMap<Key, Container, HashFunc> m_hashMap;
	class HIterator : public GMap<Key, Value>::Iterator
	{
	public:
		HIterator(const typename Poco::HashMap<Key, Container, HashFunc>::Iterator& hIt,
				const typename Poco::HashMap<Key, Container, HashFunc>::Iterator& endhIt) :
				m_hIter(hIt), m_endhIter(endhIt)
		{
			if (m_hIter != m_endhIter)
				m_lIter = m_hIter->second.begin();
		}
		HIterator(const typename Poco::HashMap<Key, Container, HashFunc>::Iterator& hIt,
			const typename Poco::HashMap<Key, Container, HashFunc>::Iterator& endhIt,
			const typename Container::iterator &lIt) : m_hIter(hIt), m_endhIter(endhIt), m_lIter(lIt)
		{
		}
		HIterator(const HIterator& hIt) : m_hIter(hIt.m_hIter),
			m_endhIter(hIt.m_endhIter), m_lIter(hIt.m_lIter)
		{
		}
		virtual ~HIterator() {}
		typename GMap<Key, Value>::Iterator* clone();
		const Key& getKey();
		Value& getValue();
		typename GMap<Key, Value>::Iterator& operator++();
		typename GMap<Key, Value>::Iterator& operator++(int);
		bool operator==(const typename GMap<Key, Value>::Iterator&) const;
		bool operator!=(const typename GMap<Key, Value>::Iterator&) const;

		typename Poco::HashMap<Key, Container, HashFunc>::Iterator getOrigIter() const
        {
            return m_hIter;
        }

	private:
		typename Poco::HashMap<Key, Container, HashFunc>::Iterator m_hIter;
		typename Poco::HashMap<Key, Container, HashFunc>::Iterator m_endhIter;
		typename Container::iterator m_lIter;
	};
};

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, Container, HashFunc>::insert(const Key& key, const Value& value)
{
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator iter = m_hashMap.find(key);
	typename Container::iterator lIter;
	if (iter == m_hashMap.end())
	{
		Container values;
		lIter = values.insert(values.end(), value);
		std::pair<typename Poco::HashMap<Key, Container, HashFunc>::Iterator, bool> pp;
		pp = m_hashMap.insert(typename Poco::HashMap<Key, Container, HashFunc>::PairType(key, values));
		iter = pp.first;
	}
	else
	{
		Container& values = iter->second;
		values.push_back(value);
		lIter = values.begin();
	}

	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(iter, m_hashMap.end(), lIter));
	return itPtr;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
int GHashMultiMap<Key, Value, Container, HashFunc>::erase(const Key& key)
{
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator it = m_hashMap.find(key);
	int size = (it != m_hashMap.end()) ? it->second.size() : 0;
	return size;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
void GHashMultiMap<Key, Value, Container, HashFunc>::erase(typename GMap<Key, Value>::IterPtr position)
{
    HIterator* hIt = dynamic_cast<HIterator*>(position.get());
    assert(hIt != 0);
    m_hashMap.erase(hIt->getOrigIter());
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, Container, HashFunc>::find(const Key& key)
{
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator it = m_hashMap.find(key);
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it, m_hashMap.end()));
	return itPtr;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, Container, HashFunc>::begin()
{
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator it = m_hashMap.begin();
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it, m_hashMap.end()));
	return itPtr;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, Container, HashFunc>::end()
{
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator it = m_hashMap.end();
	typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it, m_hashMap.end()));
	return itPtr;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::Range GHashMultiMap<Key, Value, Container, HashFunc>::equal_range(const Key& key)
{
	pair<typename Poco::HashMap<Key, Container, HashFunc>::Iterator, typename Poco::HashMap<Key, Container, HashFunc>::Iterator> eqRet;
	typename Poco::HashMap<Key, Container, HashFunc>::Iterator iter;
	iter = m_hashMap.find(key);
	typename GMap<Key, Value>::IterPtr itPtrF(new HIterator(iter, m_hashMap.end(), iter->second.begin()));
	typename GMap<Key, Value>::IterPtr itPtrL(new HIterator(iter, m_hashMap.end(), iter->second.end()));
	return typename GMap<Key, Value>::Range(itPtrF, itPtrL);
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::Iterator* GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::clone()
{
	return new HIterator(*this);
}

template<typename Key, typename Value, typename Container, typename HashFunc>
const Key& GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::getKey()
{
	return m_hIter->first;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
Value& GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::getValue()
{
	return *m_lIter;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::operator++()
{
	if (m_hIter != m_endhIter)
	{
		Container& values = m_hIter->second;
		if (m_lIter != values.end())
			m_lIter++;
		else if (++m_hIter != m_endhIter)
		{
			values = m_hIter->second;
			m_lIter = values.begin();
		}
	}
	return *this;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::operator++(int)
{
	if (m_hIter != m_endhIter)
	{
		Container& values = m_hIter->second;
		if (m_lIter != values.end())
			++m_lIter;
		else if (++m_hIter != m_endhIter)
		{
			values = m_hIter->second;
			m_lIter = values.begin();
		}
	}
	return *this;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
bool GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::operator==(const typename GMap<Key, Value>::Iterator& it) const
{
	const HIterator& hIt = dynamic_cast<const HIterator&>(it);
	if (m_hIter == hIt.m_hIter)
	{
		if (m_hIter == m_endhIter)
			return true;
		return (m_lIter == hIt.m_lIter);
	}
	return false;
}

template<typename Key, typename Value, typename Container, typename HashFunc>
bool GHashMultiMap<Key, Value, Container, HashFunc>::HIterator::operator!=(const typename GMap<Key, Value>::Iterator& it) const
{
	return !operator==(it);
}

#endif // GHASHMAP_H
